const PENDING = 'pending';//进行中
const FULFILLED = 'fulfilled';//完成态
const REJECTED = 'rejected';//拒绝或者说失败态
//Promise Resolution Procedure [[Resolve]](promise2, x)
function resolutionProcedure(promise2,x,resolve,reject){
    resolve(x);
}
class Promise<T> {
    state = PENDING //当刚创建Promise的时候初始状态是pending
    value //存放成功的值，这也是一个实例属性
    reason//存放失败的原因，这也是一个实例属性
    //2.2.6 then方法可以在同一个promise上多次调用。
    onResolvedCallbacks=[]
    onRejectedCallbacks=[]
    constructor(executor) {
        //调用resolve可以传递成功的值，并且可以把状态改为FULFILLED
        const resolve = (value: T) => {
            //2.1.3 处于rejected状态的promise：不能转换为其他任何状态。
            //2.2.2.3 它不能被调用多次。
            if (this.state === PENDING) {
                this.state = FULFILLED;//状态变成成功态
                //2.1.2.2 必须具有一个值，该值不得更改。
                this.value = value;//值为成功的结果
                //当调用resolve方法成功了就执行成功的回调
                //2.2.2.1 它必须在promise实现后调用，并以promise的值作为其第一个参数。
                //2.2.6.1 如果当promise被实现时，所有相应的onFulfilled回调函数必须按照它们发起then调用的顺序执行。
                this.onResolvedCallbacks.forEach(fn=>fn());
            }
        }
        //调用reject可以传递失败的原因，并且可以把状态改为REJECTED
        const reject = (reason) => {
            //2.1.2 处于fulfilled状态的promise：不能转换为其他任何状态。
            //2.2.3.3 它不能被调用多次。
            if (this.state === PENDING) {
                this.state = REJECTED;//状态变成失败态
                //2.1.3.2 必须具有一个原因，该原因不得更改。
                this.reason = reason;//记录失败的原因
                //当调用reject方法失败了就调用失败的回调
                //2.2.3.1 它必须在promise被拒绝后调用，并以promise的原因作为其第一个参数。
                //2.2.3.2 在promise被拒绝之前不得调用它。
                //2.2.6.2 如果当promise被拒绝时，所有相应的onRejected回调函数必须按照它们发起then调用的顺序执行。
                this.onRejectedCallbacks.forEach(fn=>fn());
            }
        }
        //传递resolve和reject并执行executor函数
        executor(resolve, reject);
    }
    settle(onfulfilled,promise2,resolve,reject){
        queueMicrotask(() => {
            try {
                //2.2.5 onFulfilled和onRejected必须作为函数被调用（即没有this值）
                const x = onfulfilled(this.value);//value+'a'
                //2.2.7.1 如果onFulfilled或onRejected返回一个值x，
                //则运行Promise Resolution Procedure [[Resolve]](promise2, x)。
                resolutionProcedure(promise2,x,resolve,reject)
            } catch (e) {
                //2.2.7.2如果onFulfilled或onRejected抛出异常e，则promise2必须以e作为原因被拒绝。
                reject(e);
            }
        });
    }
    //promise必须提供一个then方法以访问其当前或最终的值或原因。
    //指定成功和失败的回调
    //一个promise的then方法接受两个参数：
    //2.2.1 onFulfilled和onRejected都是可选参数
    then(
        onfulfilled?: (value: any) => any,
        onrejected?: (reason: any) => any): Promise<any> {
        //2.2.3 then方法必须返回一个promise
        let promise2 = new Promise((resolve, reject) => {
            //2.2.1.1 如果onFulfilled不是一个函数，它必须被忽略。
            if (!onfulfilled || typeof onfulfilled !== 'function') {
                //2.2.7.3如果onFulfilled不是一个函数且promise1被实现，则promise2必须以与promise1相同的值被实现。
                onfulfilled = value => value;
            }
            //2.2.1.2 如果onRejected不是一个函数，它必须被忽略。
            if (!onrejected || typeof onrejected !== 'function') {
                //2.2.7.4 如果onRejected不是一个函数且promise1被拒绝，则promise2必须以与promise1相同的原因被拒绝。
                onrejected = reason => { throw reason };
            }
            //2.2.2 如果onFulfilled是一个函数：
            //2.2.3 如果onRejected是一个函数：
            //如果调用then方法的时候状态是成功态
            if (this.state === FULFILLED) {
                //直接马上调用成功的回调并且传递成成功的值
                //2.2.2.1 它必须在promise实现后调用，并以promise的值作为其第一个参数。
                //2.2.2.2 在promise实现之前不得调用它。
                //2.2.4. onFulfilled或onRejected不能在执行上下文堆栈中只包含平台代码之前调用。[ 3.1]。
                this.settle(onfulfilled,promise2,resolve,reject);
            }
            //如果调用then的时候状态是失败态
            if (this.state === REJECTED) {
                //直接马上调用失败的回调函数并且传递失败的原因
                //2.2.3.1 它必须在promise被拒绝后调用，并以promise的原因作为其第一个参数。
                this.settle(onrejected,promise2,resolve,reject);
            }
            //如果调用then的时候状态是进行中
            if (this.state === PENDING) {
                //缓存成功和失败的回调
                //2.2.2.1 它必须在promise实现后调用，并以promise的值作为其第一个参数。
                this.onResolvedCallbacks.push(() => {
                    this.settle(onfulfilled,promise2,resolve,reject);
                });
                //2.2.3.1 它必须在promise被拒绝后调用，并以promise的原因作为其第一个参数。
                this.onRejectedCallbacks.push(() => {
                    this.settle(onrejected,promise2,resolve,reject);
                });
            }
        });
        //2.2.3 then方法必须返回一个promise
        return promise2;
    }
}
export default Promise;